/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.controller.admin;

import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.SimpleRequestMessage;
import cn.easyplatform.messages.request.admin.ResourceSaveRequestMessage;
import cn.easyplatform.messages.request.admin.ServiceRequestMessage;
import cn.easyplatform.messages.vos.admin.ResourceVo;
import cn.easyplatform.messages.vos.admin.ServiceVo;
import cn.easyplatform.spi.service.AdminService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ServiceType;
import cn.easyplatform.type.StateType;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.service.ServiceLocator;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.*;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class JobController extends SelectorComposer<Component> implements EventListener {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private ResourceVo rv;

    @Wire("radiogroup#serviceOp")
    private Radiogroup serviceOp;

    @Wire("label#startTime")
    private Label startTime;

    @Wire("label#prevTime")
    private Label prevTime;

    @Wire("label#nextTime")
    private Label nextTime;

    @Wire("listbox#jobProperties")
    private Listbox jobProperties;

    @Wire("listbox#jobs")
    private Listbox jobs;

    @Wire("grid#customJobs")
    private Grid customJobs;

    @Override
    public void doAfterCompose(Component comp) throws Exception {
        super.doAfterCompose(comp);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(new SimpleRequestMessage(ServiceType.JOB));
        if (resp.isSuccess()) {
            List<ResourceVo> services = (List<ResourceVo>) resp.getBody();
            for (ResourceVo s : services) {
                Listitem item = new Listitem();
                item.appendChild(new Listcell(s.getId()));
                item.appendChild(new Listcell(s.getName()));
                item.setValue(s);
                jobs.appendChild(item);
            }
            if (!services.isEmpty()) {
                jobs.setSelectedIndex(0);
                ResourceVo vo = jobs.getSelectedItem().getValue();
                select(vo);
            }
            SimpleRequestMessage req = new SimpleRequestMessage(ServiceType.JOB);
            req.setActionFlag(1);
            resp = as.getServices(req);
            if (resp.isSuccess()) {
                redraw((Collection<Map<String, Object>>) resp.getBody());
            } else {
                MessageBox.showMessage(resp);
                comp.detach();
            }
        } else {
            MessageBox.showMessage(resp);
            comp.detach();
        }
    }


    private void select(ResourceVo vo) {
        this.rv = vo;
        Listitem item = new Listitem();
        item.appendChild(new Listcell("ID"));
        item.appendChild(new Listcell(rv.getId()));
        item.setParent(jobProperties);
        item = new Listitem();
        item.appendChild(new Listcell(Labels.getLabel("admin.project.name")));
        Textbox tb = new Textbox(rv.getName());
        tb.setHflex("1");
        tb.setInplace(true);
        Listcell cell = new Listcell();
        cell.appendChild(tb);
        item.appendChild(cell);
        item.setParent(jobProperties);
        for (Map.Entry<String, String> entry : rv.getProps().entrySet()) {
            item = new Listitem();
            item.appendChild(new Listcell(entry.getKey()));
            cell = new Listcell();
            tb = new Textbox((String) entry.getValue());
            tb.setHflex("1");
            tb.setInplace(true);
            cell.appendChild(tb);
            item.appendChild(cell);
            jobProperties.appendChild(item);
        }
        serviceOp.setSelectedIndex(rv.getState() - 1);
        setState();
        setRtInfo(rv.getRuntimeInfo());
    }

    @Listen("onSelect=#jobs")
    public void onSelect() {
        ResourceVo vo = jobs.getSelectedItem().getValue();
        jobProperties.getItems().clear();
        select(vo);
    }

    private void setRtInfo(Map<String, Object> rt) {
        if (rt == null) {
            startTime.setValue(null);
            prevTime.setValue(null);
            nextTime.setValue(null);
        } else {
            Date date = (Date) rt.get("service.start.time");
            if (date != null)
                startTime.setValue(DateFormatUtils.format(date,
                        "yyyy-MM-dd hh:mm:ss"));
            else
                startTime.setValue(null);
            date = (Date) rt.get("service.prev.time");
            if (date != null)
                prevTime.setValue(DateFormatUtils.format(date,
                        "yyyy-MM-dd hh:mm:ss"));
            else
                prevTime.setValue(null);
            date = (Date) rt.get("service.next.time");
            if (date != null)
                nextTime.setValue(DateFormatUtils.format(date,
                        "yyyy-MM-dd hh:mm:ss"));
            else
                nextTime.setValue(null);
        }
        rv.setRuntimeInfo(rt);
    }

    private void setState() {
        if (rv.getState() == StateType.STOP) {
            serviceOp.getItemAtIndex(0).setDisabled(true);
            serviceOp.getItemAtIndex(1).setDisabled(false);
            serviceOp.getItemAtIndex(2).setDisabled(true);
            serviceOp.getItemAtIndex(3).setDisabled(true);
        } else if (rv.getState() == StateType.START) {
            serviceOp.getItemAtIndex(0).setDisabled(false);
            serviceOp.getItemAtIndex(1).setDisabled(true);
            serviceOp.getItemAtIndex(2).setDisabled(false);
            serviceOp.getItemAtIndex(3).setDisabled(true);
        } else if (rv.getState() == StateType.PAUSE) {
            serviceOp.getItemAtIndex(0).setDisabled(false);
            serviceOp.getItemAtIndex(1).setDisabled(true);
            serviceOp.getItemAtIndex(2).setDisabled(true);
            serviceOp.getItemAtIndex(3).setDisabled(false);
        } else {
            serviceOp.getItemAtIndex(0).setDisabled(false);
            serviceOp.getItemAtIndex(1).setDisabled(true);
            serviceOp.getItemAtIndex(2).setDisabled(false);
            serviceOp.getItemAtIndex(3).setDisabled(true);
        }
    }

    @Listen("onCheck=#serviceOp")
    public void onOp() {
        if (this.rv == null)
            return;
        String msg = null;
        if (serviceOp.getSelectedIndex() == 0)
            msg = Labels.getLabel("admin.service.stop");
        else if (serviceOp.getSelectedIndex() == 1)
            msg = Labels.getLabel("admin.service.start");
        else if (serviceOp.getSelectedIndex() == 2)
            msg = Labels.getLabel("admin.service.pause");
        else
            msg = Labels.getLabel("admin.service.resume");
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{msg}), Labels
                        .getLabel("admin.service.op.title"), Messagebox.CANCEL
                        | Messagebox.OK, Messagebox.QUESTION,
                new EventListener<Event>() {

                    @Override
                    public void onEvent(Event evt) throws Exception {
                        int state = rv.getState();
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            rv.setState(serviceOp.getSelectedIndex() + 1);
                            AdminService as = ServiceLocator
                                    .lookup(AdminService.class);
                            IResponseMessage<?> resp = as
                                    .setServiceState(new ServiceRequestMessage(
                                            new ServiceVo(rv.getId(), ServiceType.JOB, rv.getState())));
                            if (resp.isSuccess()) {
                                if (serviceOp.getSelectedIndex() == 3) {
                                    serviceOp.setSelectedIndex(1);
                                }
                                setState();
                                if (resp.getBody() != null) {
                                    Map<String, Object> rt = (Map<String, Object>) resp.getBody();
                                    setRtInfo(rt);
                                } else
                                    setRtInfo(null);
                            } else {
                                serviceOp.setSelectedIndex(state - 1);
                                MessageBox.showMessage(resp);
                            }
                        } else
                            serviceOp.setSelectedIndex(state - 1);
                    }
                });
    }

    @Listen("onClick=#add")
    public void onAdd() {
        if (this.rv == null || jobs.getSelectedItem() == null)
            return;
        Listitem item = new Listitem();
        Listcell cell = new Listcell();
        Textbox tb = new Textbox("key");
        tb.setHflex("1");
        tb.setInplace(true);
        cell.appendChild(tb);
        cell.setParent(item);
        cell = new Listcell();
        tb = new Textbox("value");
        tb.setHflex("1");
        tb.setInplace(true);
        cell.appendChild(tb);
        cell.setParent(item);
        jobProperties.appendChild(item);
    }

    @Listen("onClick=#save")
    public void onSave(Event evt) {
        if (this.rv == null || jobs.getSelectedItem() == null)
            return;
        List<Listitem> items = jobProperties.getItems();
        for (int i = 2; i < items.size(); i++) {
            Listitem li = items.get(i);
            Listcell cell = (Listcell) li.getFirstChild();
            String name = null;
            if (cell.getFirstChild() == null)
                name = cell.getLabel();
            else
                name = ((Textbox) cell.getFirstChild()).getValue();
            cell = (Listcell) li.getLastChild();
            Textbox tb = (Textbox) cell.getFirstChild();
            // 空值去掉
            if (Strings.isBlank(name) || Strings.isBlank(tb.getValue()))
                rv.getProps().remove(name);
            else
                rv.getProps().put(name, tb.getValue());
        }
        AdminService as = ServiceLocator.lookup(AdminService.class);
        rv.setName(((Textbox) jobProperties.getItemAtIndex(1).getLastChild().getFirstChild()).getValue());
        IResponseMessage<?> resp = as.saveResource(new ResourceSaveRequestMessage(rv));
        if (resp.isSuccess()) {
            Button btn = (Button) evt.getTarget();
            MessageBox.showInfo(Labels.getLabel("admin.service.op.title"), Labels.getLabel("common.success", new String[]{btn.getLabel()}));
        } else
            MessageBox.showMessage(resp);
    }

    @Listen("onClick=#remove")
    public void onRemove() {
        final Listitem li = jobProperties.getSelectedItem();
        if (li == null)
            return;
        String name = null;
        Listcell cell = (Listcell) li.getFirstChild();
        if (cell.getFirstChild() == null)
            name = cell.getLabel();
        else
            name = ((Textbox) cell.getFirstChild()).getValue();
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{Labels.getLabel("admin.project.property.remove")
                        + name}), Labels.getLabel("admin.service.op.title"),
                Messagebox.CANCEL | Messagebox.OK, Messagebox.QUESTION,
                new EventListener<Event>() {

                    @Override
                    public void onEvent(Event evt) throws Exception {
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            li.detach();
                        }
                    }
                });
    }
    ///////////////动态任务//////////////////////

    private void redraw(Collection<Map<String, Object>> services) {
        services.forEach(rv -> {
            Row row = new Row();
            row.appendChild(new Label((String) rv.get("id")));
            row.appendChild(new Label((String) rv.get("user")));//用户id
            row.appendChild(new Label((String) rv.get("entity")));//执行逻辑
            row.appendChild(new Label((String) rv.get("name")));//执行逻辑

            Div div = new Div();
            Datebox datebox = new Datebox();
            datebox.setHflex("1");
            datebox.setFormat("yyyy-MM-dd HH:mm:ss");
            datebox.setValue((Date) rv.get("service.start.time"));
            div.appendChild(datebox);
            Button modify = new Button(Labels.getLabel("admin.job.modify"));
            modify.setHflex("1");
            modify.setSclass("ml-1");
            modify.addEventListener(Events.ON_CLICK, this);
            div.appendChild(modify);
            row.appendChild(div);

            Button del = new Button(Labels.getLabel("debug.log.stop"));
            del.setHflex("1");
            del.addEventListener(Events.ON_CLICK, this);
            row.appendChild(del);

            row.setValue(rv);
            customJobs.getRows().appendChild(row);
        });
    }

    @Listen("onClick=#refresh")
    public void onRefresh(Event event) {
        SimpleRequestMessage req = new SimpleRequestMessage(ServiceType.JOB);
        req.setActionFlag(1);
        AdminService as = ServiceLocator.lookup(AdminService.class);
        IResponseMessage<?> resp = as.getServices(req);
        if (resp.isSuccess()) {
            customJobs.getRows().getChildren().clear();
            redraw((Collection<Map<String, Object>>) resp.getBody());
        } else
            Clients.wrongValue(event.getTarget(), resp.getCode() + ":" + resp.getBody());
    }

    @Listen("onClick=#reload")
    public void onReload(Event event) {
        setServiceState(new ServiceVo(null, ServiceType.JOB, StateType.START), Labels.getLabel("admin.project.load.db"), event, 3);
    }

    @Listen("onClick=#clear")
    public void onClear(Event event) {
        setServiceState(new ServiceVo(null, ServiceType.JOB, StateType.STOP), Labels.getLabel("debug.clear"), event, 2);
    }

    @Override
    public void onEvent(Event event) throws Exception {
        Map<String, Object> data;
        if (event.getTarget().getParent() instanceof Row) {//停止
            data = ((Row) event.getTarget().getParent()).getValue();
            ServiceVo sv = new ServiceVo(null, ServiceType.JOB, StateType.STOP);
            sv.setValue("id", data.get("id"));
            setServiceState(sv, Labels.getLabel("debug.log.stop"), event, 1);
        } else {//修改时间
            data = ((Row) event.getTarget().getParent().getParent()).getValue();
            ServiceVo sv = new ServiceVo(null, ServiceType.JOB, StateType.RESET);
            sv.setValue("id", data.get("id"));
            sv.setValue("time", ((Datebox) event.getTarget().getPreviousSibling()).getValue());
            setServiceState(sv, Labels.getLabel("admin.job.modify"), event, 0);
        }
    }

    private void setServiceState(ServiceVo sv, String topic, Event event, int action) {
        Messagebox.show(Labels.getLabel("admin.service.op.confirm",
                new Object[]{topic}), Labels.getLabel("admin.service.op.title"),
                Messagebox.CANCEL | Messagebox.OK, Messagebox.QUESTION,
                new EventListener<Event>() {
                    @Override
                    public void onEvent(Event evt) throws Exception {
                        if (evt.getName().equals(Messagebox.ON_OK)) {
                            AdminService as = ServiceLocator.lookup(AdminService.class);
                            IResponseMessage<?> resp = as.setServiceState(new ServiceRequestMessage(sv));
                            if (resp.isSuccess()) {
                                if (action > 1)
                                    customJobs.getRows().getChildren().clear();
                                if (action == 1) {
                                    event.getTarget().getParent().detach();
                                } else if (action == 3) {
                                    redraw((Collection<Map<String, Object>>) resp.getBody());
                                }
                                if (action == 0) {
                                    boolean flag = (Boolean) resp.getBody();
                                    if (flag)
                                        MessageBox.showInfo(Labels.getLabel("admin.service.op.title"), Labels.getLabel("common.success", new Object[]{topic}));
                                    else
                                        MessageBox.showMessage(Labels.getLabel("admin.service.op.title"), Labels.getLabel("common.fail", new Object[]{topic}));
                                }
                            } else Clients.wrongValue(event.getTarget(), resp.getCode() + ":" + resp.getBody());
                        }
                    }
                });
    }
}
